package com.feonix.common.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.AnnotationUtils;

import com.feonix.common.annotation.AnnotationBean;

public class AnnotationUtil {

	protected static Log logger = LogFactory.getLog(AnnotationUtil.class);

	public static <T extends Annotation> T findAnnotationFromMethod(Class<?> clazz, String methodName,
			Class<T> annotation) {
		T tmpAnnotation = null;
		try {
			Method method = clazz.getMethod(methodName, new Class[0]);
			tmpAnnotation = method.getAnnotation(annotation);
		} catch (Exception exception) {
			logger.error("获得方法的注释出错", exception);
		}
		return tmpAnnotation;
	}

	public static <T extends Annotation> T findAnnotationFromField(Class<?> clazz, String fieldName,
			Class<T> annotation) {
		T tmpAnnotation = null;
		try {
			Field field = clazz.getDeclaredField(fieldName);
			tmpAnnotation = field.getAnnotation(annotation);
		} catch (Exception exception) {
			logger.error("获得属性的注释出错", exception);
		}
		return tmpAnnotation;
	}

	public static <T extends Annotation> T findAnnotationFromClass(Class<?> clazz, Class<T> annotation) {
		T tmpAnnotation = null;
		try {
			tmpAnnotation = clazz.getAnnotation(annotation);
		} catch (Exception exception) {
			logger.error("获得属性的注释出错", exception);
		}
		return tmpAnnotation;
	}

	public static <T extends Annotation> List<AnnotationBean<T>> findAnnotationFromFields(Class<?> clazz,
			Class<T> annotation) {
		ArrayList<AnnotationBean<T>> annotationBeanList = new ArrayList<AnnotationBean<T>>();

		Class<?> superClazz = clazz.getSuperclass();
		Iterator<AnnotationBean<T>> annotationBeanIterator;
		AnnotationBean<T> annotationBean;
		if ((superClazz != null) && (superClazz != Object.class)) {
			List<AnnotationBean<T>> tmpAnnotationBeanList = findAnnotationFromFields(superClazz, annotation);
			for (annotationBeanIterator = tmpAnnotationBeanList.iterator(); annotationBeanIterator.hasNext();) {
				annotationBean = annotationBeanIterator.next();
				if (!(annotationBeanList.contains(annotationBean))) {
					annotationBeanList.add(annotationBean);
				}
			}
			tmpAnnotationBeanList.clear();
		}
		Field[] fields = clazz.getDeclaredFields();
		if (fields != null) {
			annotationBean = null;
			annotationBeanIterator = null;
			for (Field field : fields) {
				T tmpAnnotation = field.getAnnotation(annotation);
				if (tmpAnnotation == null) {
					continue;
				}
				annotationBean = new AnnotationBean<T>();
				annotationBean.setName(field.getName());
				annotationBean.setFieldType(field.getType());
				annotationBean.setAnnotation(tmpAnnotation);
				annotationBean.setField(field);
				annotationBeanList.add(annotationBean);
			}
		}
		return annotationBeanList;
	}

	public static List<Field> findNoAnnotationFields(Class<?> clazz) {
		ArrayList<Field> arrayList = null;
		Field[] arrayOfField1 = clazz.getDeclaredFields();
		Annotation[] arrayOfAnnotation = null;
		if (arrayOfField1 != null) {
			arrayList = new ArrayList<Field>();
			for (Field field : arrayOfField1) {
				arrayOfAnnotation = field.getAnnotations();
				if (ArrayUtils.isEmpty(arrayOfAnnotation)) {
					arrayList.add(field);
				}
			}
		}
		return arrayList;
	}

	public static <T extends Annotation> AnnotationBean<T> findAnnotationFromField(Class<?> clazz,
			Class<T> annotation) {
		AnnotationBean<T> annotationBean = null;
		Field[] arrayOfField1 = clazz.getDeclaredFields();
		if (arrayOfField1 != null) {
			T localAnnotation = null;
			for (Field localField : arrayOfField1) {
				localAnnotation = localField.getAnnotation(annotation);
				if (localAnnotation == null) {
					continue;
				}
				annotationBean = new AnnotationBean<T>();
				annotationBean.setName(localField.getName());
				annotationBean.setFieldType(localField.getType());
				annotationBean.setAnnotation(localAnnotation);
				annotationBean.setField(localField);
				break;
			}
		}

		return annotationBean;
	}

	public static <T extends Annotation> boolean isThisAnnotation(Class<?> clazz, Class<T> annotation) {
		return clazz.isAnnotationPresent(annotation);
	}

	public static Object getValue(Annotation annotation, String attr) {
		return AnnotationUtils.getValue(annotation, attr);
	}

	public static boolean hasValue(Annotation annotation, String attr) {
		return (getValue(annotation, attr) != null);
	}

}
